﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Moss2007 = Microsoft.SharePoint;
using System.IO;


namespace ExportHub2007Content
{
    class Exporter
    {
        private StreamWriter _logFile;
        private string _sourceUrl = "";
        private bool _testMode = false;


        public Exporter(StreamWriter logFile, bool testMode)
        {
            if (logFile == null)
            {
                throw new ArgumentNullException("logFile");
            }

            _testMode = testMode;

            _logFile = logFile;
        }

        public string SourceUrl
        {
            get { return _sourceUrl; }
            set { _sourceUrl = value; }
        }


        public bool IsSourceValid(string sourceUrl)
        {
            using (Moss2007.SPSite site = new Moss2007.SPSite(sourceUrl))
            {
                Moss2007.SPWeb hubWeb = site.OpenWeb();
                Moss2007.SPList contentLib = hubWeb.Lists["ProdHub Content Library"];
                if (contentLib.ItemCount > 0)
                {
                    Log("Found " + contentLib.ItemCount.ToString() + " items in the content library to export");
                    return true;
                }
                else
                {
                    Log("No content library items were found - migration aborted");
                    return false;
                }
            }
        }


        private void Log(string message)
        {
            if (_logFile != null)
            {
                Console.WriteLine(message);
                _logFile.WriteLine(message);
            }
        }

        private void ExportContentLibrary()
        {
            List<ContentLibraryItem> exportedContentLibItems = new List<ContentLibraryItem>();

            using (Moss2007.SPSite site = new Moss2007.SPSite(this.SourceUrl))
            {
                using (Moss2007.SPWeb hubWeb = site.OpenWeb())
                {
                    Moss2007.SPList contentLib = hubWeb.Lists["ProdHub Content Library"];

                    // setup base path for exported files
                    string basePath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "Hub2007Exported\\ContentLibrary\\");
                    FileStream fs;
                    Moss2007.SPListItem sourceItem = null;
                    string outputFile = "";

                    int itemsToExport = contentLib.ItemCount;
                    if (_testMode) itemsToExport = 5;

                    Log("ExportContentLibrary: Exporting " + itemsToExport.ToString() + " documents");

                    for (int i = 0; i < itemsToExport; i++)
                    {
                        try
                        {
                            ContentLibraryItem expItem = new ContentLibraryItem();
                            sourceItem = contentLib.Items[i];

                            expItem.Title = (string)sourceItem["Title"];
                            expItem.Product = (string)sourceItem["Product"];

                            string tempProducts = expItem.Product.Replace(";#", ";").Trim(';');
                            string[] contentProducts = tempProducts.Split(';');
                            if (contentProducts.Length > 0)
                            {
                                // grab the first product that is related to this forum post
                                expItem.Product = contentProducts[0];
                                if (contentProducts.Length > 1)
                                {
                                    Log("The content library is associated to more than one product. Export will associate this item with its first product association which is " + contentProducts[0]);
                                }
                            }

                            expItem.Abstract = (string)sourceItem["ContentDescription"];
                            expItem.AppearsInRotator = (bool)sourceItem["AppearsInRotator"];
                            expItem.ScreenCaptureImage = (string)sourceItem["ScreenCaptureImage"];
                            expItem.IsVideoContent = (bool)sourceItem["IsVideoContent"];
                            expItem.IsFeaturedContent = (bool)sourceItem["IsFeaturedContent"];
                            expItem.Difficulty = (string)sourceItem["Difficulty"];

                            Moss2007.SPFile file = sourceItem.File;
                            outputFile = basePath + file.Name;

                            expItem.FileName = file.Name;

                            fs = new FileStream(outputFile, FileMode.Create);

                            Log("ExportContentLibrary: Exporting file: " + outputFile);
                            byte[] fileBytes = file.OpenBinary(Moss2007.SPOpenBinaryOptions.SkipVirusScan);

                            fs.Write(fileBytes, 0, fileBytes.Length);

                            fs.Close();
                            fs.Dispose();

                            Log("ExportContentLibrary: Capturing metadata for file: " + expItem.Title);
                            exportedContentLibItems.Add(expItem);
                        }
                        catch (Exception err)
                        {
                            Log("Unexpected error occurred:");
                            Log(err.Message + err.StackTrace);
                        }

                    }

                    // export the List<> as XML using serializer
                    Log("ExportContentLibrary: Exporting metadata as XML file");
                    string outputFileXml = basePath + "ContentLibraryMetadata.xml";
                    FileStream fs2 = new FileStream(outputFileXml, FileMode.Create);
                    System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(List<ContentLibraryItem>));
                    xs.Serialize(fs2, exportedContentLibItems);
                    fs2.Close();
                    Log("ExportContentLibrary: Done exporting");

                }
            }
        }

        private void ExportProductList()
        {
            List<Product> exportedProductItems = new List<Product>();

            using (Moss2007.SPSite site = new Moss2007.SPSite(this.SourceUrl))
            {
                using (Moss2007.SPWeb hubWeb = site.OpenWeb())
                {
                    Moss2007.SPList productsList = hubWeb.Lists["Products"];

                    // setup base path for exported XML ("Hub2007Exported\\ProductsList");
                    string basePath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "Hub2007Exported\\ProductsList\\");

                    Moss2007.SPListItem sourceItem = null;

                    int itemsToExport = productsList.ItemCount;
                    Log("ExportProducts: Exporting " + itemsToExport.ToString() + " products");

                    for (int i = 0; i < itemsToExport; i++)
                    {
                        try
                        {
                            Product expItem = new Product();
                            sourceItem = productsList.Items[i];

                            expItem.Title = (string)sourceItem["Title"];

                            Log("ExportProducts: Capturing metadata for product: " + expItem.Title);
                            exportedProductItems.Add(expItem);
                        }
                        catch (Exception err)
                        {
                            Log("Unexpected error occurred:");
                            Log(err.Message + err.StackTrace);
                        }
                    }

                    // export the List<> as XML using serializer
                    Log("ExportProducts: Exporting metadata as XML file");
                    string outputFileXml = basePath + "ProductsListMetadata.xml";
                    FileStream fs2 = new FileStream(outputFileXml, FileMode.Create);
                    System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(List<Product>));
                    xs.Serialize(fs2, exportedProductItems);
                    fs2.Close();

                    Log("ExportProducts: Done exporting");
                }

            }
        }

        private void ExportCoachesList()
        {
            List<Coach> exportedCoachItems = new List<Coach>();

            using (Moss2007.SPSite site = new Moss2007.SPSite(this.SourceUrl))
            {
                using (Moss2007.SPWeb hubWeb = site.OpenWeb())
                {
                    Moss2007.SPList coachesList = hubWeb.Lists["Coaches"];

                    // setup base path for exported XML ("Hub2007Exported\\CoachesList");
                    string basePath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "Hub2007Exported\\CoachesList\\");

                    Moss2007.SPListItem sourceItem = null;

                    int itemsToExport = coachesList.ItemCount;
                    Log("ExportCoaches: Exporting " + itemsToExport.ToString() + " coach records");

                    for (int i = 0; i < itemsToExport; i++)
                    {
                        try
                        {
                            Coach expItem = new Coach();
                            sourceItem = coachesList.Items[i];

                            // The CoachName field may not be available in all 2007 builds of Hub
                            try
                            {
                                string temp = (string)sourceItem["CoachName"];
                                int id = Int32.Parse(temp.Substring(0, temp.IndexOf(';')));
                                Moss2007.SPUser user = hubWeb.AllUsers.GetByID(id);
                                expItem.DomainUserName = user.LoginName;
                            }
                            catch (Exception) { expItem.DomainUserName = ""; }

                            expItem.Availability = (string)sourceItem["Availability"];
                            expItem.ContactMethod = (string)sourceItem["ContactMethod"];
                            expItem.Features = (string)sourceItem["Feature"];
                            expItem.Group = (string)sourceItem["Group"];
                            expItem.Title = (string)sourceItem["Title"];
                            expItem.PictureUrl = (string)sourceItem["Picture"];
                            expItem.Products = (string)sourceItem["Product"];

                            Log("ExportCoaches: Capturing metadata for coach: " + expItem.Title);
                            exportedCoachItems.Add(expItem);
                        }
                        catch (Exception err)
                        {
                            Log("Unexpected error occurred:");
                            Log(err.Message + err.StackTrace);
                        }

                    }

                    // export the List<> as XML using serializer
                    Log("ExportCoaches: Exporting metadata as XML file");

                    string outputFileXml = basePath + "CoachesListMetadata.xml";
                    FileStream fs2 = new FileStream(outputFileXml, FileMode.Create);
                    System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(List<Coach>));
                    xs.Serialize(fs2, exportedCoachItems);
                    fs2.Close();

                    Log("ExportCoaches: Done exporting");

                }
            }
        }

        private string GetLoginForUserId(int userId)
        {
            try
            {
                using (Moss2007.SPSite site = new Moss2007.SPSite(this.SourceUrl))
                {
                    using (Moss2007.SPWeb hubWeb = site.OpenWeb())
                    {
                        Moss2007.SPUser user = hubWeb.AllUsers.GetByID(userId);
                        return user.LoginName;
                    }
                }
            }
            catch (Exception) { return ""; }
        }


        private List<ForumDiscussionItem> TraverseListFolder(ref Moss2007.SPList rootList, Moss2007.SPFolder folder)
        {
            Moss2007.SPQuery q = new Moss2007.SPQuery();
            q.Folder = folder;
            Moss2007.SPListItemCollection ic = rootList.GetItems(q); 
            
            List<ForumDiscussionItem> retVal = new List<ForumDiscussionItem>();

            foreach(Moss2007.SPListItem discussionItem in ic)
            {
                try
                {
                    ForumDiscussionItem expItem = new ForumDiscussionItem();
                    expItem.ID = discussionItem.ID.ToString();
                    expItem.Title = (string)discussionItem["Title"];
                    expItem.Body = (string)discussionItem["Body"];
                    expItem.TrimmedBody = (string)discussionItem["TrimmedBody"];
                    expItem.ThreadIndex = (string)discussionItem["ThreadIndex"];
                    expItem.Product = (string)discussionItem["Product"];

                    string tempProducts = expItem.Product.Replace(";#", ";").Trim(';');
                    string[] forumProducts = tempProducts.Split(';');
                    if (forumProducts.Length > 0)
                    {
                        // grab the first product that is related to this forum post
                        expItem.Product = forumProducts[0];
                        if (forumProducts.Length > 1)
                        {
                            Log("The forum post is associated to more than one product. Export will associate this item with its first product association which is " + forumProducts[0]);
                        }
                    }

                    string temp = (string)discussionItem["Author"];
                    int id = Int32.Parse(temp.Substring(0, temp.IndexOf(';')));
                    expItem.Author = GetLoginForUserId(id);

                    temp = (string)discussionItem["Editor"];
                    id = Int32.Parse(temp.Substring(0, temp.IndexOf(';')));
                    expItem.Editor = GetLoginForUserId(id);


                    if (discussionItem.Folder != null)
                    {
                        expItem.Replies = TraverseListFolder(ref rootList, discussionItem.Folder);
                    }

                    retVal.Add(expItem);
                }
                catch (Exception err)
                {
                    Log("Unexpected error occurred:");
                    Log(err.Message + err.StackTrace);
                }
            }

            return retVal;

        }

        private void ExportForums()
        {

            using (Moss2007.SPSite site = new Moss2007.SPSite(this.SourceUrl))
            {
                using (Moss2007.SPWeb hubWeb = site.OpenWeb())
                {
                    Moss2007.SPList forumsList = hubWeb.Lists["ProdHub Forums"];

                    // setup base path for exported XML ("Hub2007Exported\\Forums");
                    string basePath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "Hub2007Exported\\Forums\\");

                    int itemsToExport = forumsList.ItemCount;
                    Log("ExportForums: Exporting " + itemsToExport.ToString() + " forum posts");

                    List<ForumDiscussionItem> exportedForumItems = TraverseListFolder(ref forumsList, forumsList.RootFolder);

                    // export the List<> as XML using serializer
                    Log("ExportForums: Exporting metadata as XML file");

                    string outputFileXml = basePath + "ForumsMetadata.xml";
                    FileStream fs2 = new FileStream(outputFileXml, FileMode.Create);
                    System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(List<ForumDiscussionItem>));
                    xs.Serialize(fs2, exportedForumItems);
                    fs2.Close();

                    Log("ExportForums: Done exporting");
                }

            }
        }

        public bool PerformExport()
        {
            if (_logFile == null)
            {
                throw new InvalidOperationException("logFile was null");
            }
            if (String.IsNullOrEmpty(this.SourceUrl))
            {
                throw new InvalidOperationException("A required parameter is invalid");
            }

            try
            {
                Log("ExportHubContent started with SOURCEURL: (" + this.SourceUrl + ")");
                Log("Begin local file system check...");
                bool isDiskReady = MakeDiskReady();

                if (isDiskReady)
                {
                    Log("Begin URI validation...");

                    if (IsSourceValid(this.SourceUrl))
                    {
                        // Export content library
                        ExportContentLibrary();

                        // Export product list
                        ExportProductList();

                        // Export coaches
                        ExportCoachesList();

                        // Export forums
                        ExportForums();


                    }
                    return true;
                }
                else // disk is not ready
                {
                    Log("Local file system could not be prepared for export. Export aborted.");
                    return false;
                }
                
            }
            catch (Exception err)
            {
                Log("Unexpected error occurred:");
                Log(err.Message + err.StackTrace);
                return false;

            }
            finally
            {
                if (_logFile != null)
                {
                    _logFile.Flush();
                    _logFile.Close();
                }
            }


        }

        private bool MakeDiskReady()
        {
            
            try
            {
                // attempt create directory structure
                if (System.IO.Directory.Exists("Hub2007Exported"))
                {
                    Console.WriteLine("Warning - an existing 'Hub2007Exported' directory was found. This directory must be deleted to continue the export operation. Do you want to DELETE this directory (Y/N)?");
                    ConsoleKeyInfo response1 = Console.ReadKey(true);
                    if (response1.KeyChar == 'y' || response1.KeyChar == 'Y')
                    {
                        Log("Deleting existing 'Hub2007Exported' directory.");
                        System.IO.Directory.Delete("Hub2007Exported", true);
                    }
                    else
                    {
                        // user chose not to delete the existing directory
                        Console.WriteLine("The existing 'Hub2007Exported' directory will not be deleted. Export operation aborted by user.");
                        return false;
                    }
                }

                // continue
                Log("Creating new 'Hub2007Exported' directory structure.");
                System.IO.Directory.CreateDirectory("Hub2007Exported");
                System.IO.Directory.CreateDirectory("Hub2007Exported\\ContentLibrary");
                System.IO.Directory.CreateDirectory("Hub2007Exported\\ProductsList");
                System.IO.Directory.CreateDirectory("Hub2007Exported\\CoachesList");
                System.IO.Directory.CreateDirectory("Hub2007Exported\\Forums");
                

                // verify disk space
                System.IO.DriveInfo di = new DriveInfo(System.IO.Directory.GetCurrentDirectory());
                // recommend at least 1 GB of free space on the local disk
                long freeBytes = di.AvailableFreeSpace;
                long freeMbytes = freeBytes / 1024 / 1024;
                Log("Current disk has " + freeMbytes.ToString() + " MB free.");

                if (freeMbytes <= 1000)
                {
                    Console.WriteLine("Local disk may not have enough space to save all the exported files. Make sure there is at least 1000 MB available space on this disk");
                    return false;
                }


                return true;
            }
            catch (Exception err)
            {
                Log("Unexpected error during disk check: " + err.Message);
                return false;

            }
            

        }

    }
}
